/**
 * ajax框架类，提供五个对外接口.
 * 一般情况下都是异步请求(同步用ajax没有意义)asynchronous可以不用传入
 * 第三个参数extend为callbackFunction的扩展参数,可以不传入，后面有其他参数同时没有扩展参数可以传入null
 * coos.ajax.get(url,callbackFunction,extend,asynchronous)
 * coos.ajax.post(url,callbackFunction,formElement,extend,encode,asynchronous)
 * coos.ajax.postText(url,callbackFunction,formElement,extend,asynchronous)
 * coos.ajax.postUnencode(url,callbackFunction,formElement,extend,asynchronous)
 * coos.ajax.jsonp(url,callbackFunction,responseName,extend)
 */
coos.ajax = function()
{
	this.version = "1.0";
};

/**
 * 创建XMLHttpRequest工厂类
 */
coos.ajax.createRequest = function()
{
	var objXMLHttp = null;

	if (window.XMLHttpRequest)
	{
		objXMLHttp = new XMLHttpRequest();
	    
		if (objXMLHttp.overrideMimeType)
		{
			objXMLHttp.overrideMimeType('text/xml');
		}
	}
	else
	{
	    var MSXML = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'MSXML2.XMLHTTP.5.0', 'MSXML2.XMLHTTP.4.0', 'MSXML2.XMLHTTP.3.0'];
	    
	    for(var n = 0; n < MSXML.length; n++)
	    {
	        try
	        {
	            objXMLHttp = new ActiveXObject(MSXML[n]);        
	            break;
	        }
	        catch(e) {}
	    }
	}
	
  	return objXMLHttp;
};

/**
 * 本域get请求
 * @param url 请求相对路径
 * @param callbackFunction 回调函数
 * @param extend 回调函数扩展参数(json格式)
 * @param asynchronous 是否为异步请求，默认为true
 * @example
function testGet()
{
	var url = "ajax_test.action?type=localhost";
	coos.ajax.get(url,getCallback,{test1:'aaa1',test2:'bbb1'});
	//coos.ajax.get(url,function(test1,test2,responseText){alert(responseText);alert(test1);},{test1:'aaa1',test2:'bbb1'});
}
function getCallback(responseText,test1,test2)
{
	alert("getCallback responseText = " + responseText);
	alert("getCallback message = " + responseText.toJson().message);
	alert("getCallback test1 = " + test1);
}
 */
coos.ajax.get = function(url,callbackFunction,extend,asynchronous)
{
	var http_request = coos.ajax.createRequest();
	coos.ajax.bindResponse (http_request,callbackFunction,extend);		
	url = coos.url.random(url);
	asynchronous = asynchronous || true;
	http_request.open ("GET", url, asynchronous);
	
	http_request.send (null);
	
	return false;
};

/**
 * post请求
 * @param url 请求相对路径
 * @param formElement 表单对象或表单id
 * @param callbackFunction 回调函数
 * @param extend 回调函数扩展参数(json格式)
 * @param encode 编码方式text，unencode，其他，默认采用通用的两次encodeURIComponent
 * 后台解码：java.net.URLDecoder.decode(request.getParameter("name"), "UTF-8″);
 * @param asynchronous 是否为异步请求，默认为true
 * @example
function testPost()
{
	var url = "../getData?action=getPostData";
	var form = coos.$id("post_add");
	//no extend param
	//coos.ajax.post(url,postCallback,"post_add");
	
	//extend json object
	var id = form.id;
	//coos.ajax.post(url,postCallback,"post_add",{test1:id,test2:'bbb3'});
	
	//extend jsonStr
	var jsonStr = "{test1:'" + id + "',test2:'bbb3'}"
	var ext = jsonStr.toJson();
	//var ext = eval('(' + json + ')');
	coos.ajax.post(url,postCallback,"post_add",ext);
	
}
function postCallback(responseText,test1,test2)
{
	//{success:true,action:'getPostData',message:'test message'}
	alert("postCallback responseText = " + responseText);
	alert("postCallback is success = " + responseText.toJson().success);
	alert("postCallback message = " + responseText.toJson().message);
	alert("postCallback test1 = " + test1);
	alert("postCallback test2 = " + test2);
}
<form action="" id="post_add" name="post_add" method="post" onsubmit="return false;">
		<textarea name="message" id="message">test message 测试中文</textarea>
		<input type="button" id="subBtn" value="submit" onclick="testPost()" />
</form>
 */
coos.ajax.post = function(url,callbackFunction,formElement,extend,encode,asynchronous)
{
	var http_request = coos.ajax.createRequest();
	
	coos.ajax.bindResponse(http_request,callbackFunction,extend);		
	url = coos.url.random(url);
	asynchronous = asynchronous || true;
	formElement = coos.$obj(formElement);
	//获取表单内容字符串，转换比较多，需要时间比较久
	var requireString = coos.ajax.parseParameteres(formElement,encode);
	//获取字符串后再打开链接
	http_request.open("POST", url, asynchronous);
	
	http_request.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
	http_request.setRequestHeader("encoding","utf-8");
	http_request.setRequestHeader("Content-length", requireString.length);
	//在win2000下的ie6.0会导致很慢
	//jquery mootools ext中都没有此项设置,prototype-1.6下说明为了兼容低版本的Mozilla浏览器才设置的
	//http_request.setRequestHeader("Connection","close");
	
	//Mozilla浏览器post方法不能用send(null)没有内容必须用send("")
	if(requireString == null){requireString = "";}
	http_request.send(requireString);
	
	return false;
};

/**
 * 文本形式post请求(去掉换行符和html标签)
 */
coos.ajax.postText = function(url,callbackFunction,formElement,extend,asynchronous)
{
	coos.ajax.post(url,callbackFunction,formElement,extend,"text",asynchronous);
};

/**
 * 不进行编码，直接提交表单内容
 */
coos.ajax.postUnencode = function(url,callbackFunction,formElement,extend,asynchronous)
{
	coos.ajax.post(url,callbackFunction,formElement,extend,"unencode",asynchronous);
};

/**
 * 跨域请求
 * @param url 请求路径,跨域要完整的路径，本域可以是相对路径
 * @param callbackFunction 回调函数
 * @param responseName 服务端返回的变量名称,会把值自动附加到url参数中，后台可以获取到
 * @param extend 回调函数扩展参数(json格式)
 * @example
function testJsonp()
{
	var url = "http://zhengdz.iap111.com:8080/coos/coos/ajax_test.action?type=remote";
	coos.ajax.jsonp(url,jsonpCallback,"remote_request",{test1:'aaa2',test2:'bbb2'});
}
function jsonpCallback(responseText,test1,test2)
{
	alert("jsonpCallback responseText = " + responseText);
	alert("jsonpCallback message = " + responseText.toJson().message);
	alert("jsonpCallback test1 = " + test1);
}
 */
coos.ajax.jsonp = function(url,callbackFunction,responseName,extend)
{
	var script = document.createElement("script");
	script.id = "coos_jsonp_" + responseName;
	
    if(script.addEventListener)
    {
		script.addEventListener("load", function(){
			coos.ajax.jsonp.callbackHandle(callbackFunction,responseName,extend);
			}, false);
    }   
	else if(script.attachEvent)
	{
		script.attachEvent("onreadystatechange",function(){
			var target = window.event.srcElement;
			if(target.readyState == "loaded")
			{
				coos.ajax.jsonp.callbackHandle(callbackFunction,responseName,extend);
			}
			});
	}
	//通过url参数传递给后台，后台通过request获取responseName参数值获得传递过去的变量名
	if(responseName)
	{
		url = coos.url.addAttribe("responseName",responseName,url);
	}
	url = coos.url.random(url);
	script.src = url;
	coos.$head().appendChild(script);
};

/**
 * 跨域请求回调处理函数,在script脚本onload完成后执行
 * @param callbackFunction 回调函数
 * @param extend 回调函数扩展参数(json格式)
 * @param responseName 服务端返回的变量名称
 */
coos.ajax.jsonp.callbackHandle = function(callbackFunction,responseName,extend)
{
 	try
	{
		var responseText = eval(responseName);
		//非字符串类型转换为json字符串类型
		if(typeof(responseText) == "object")
		{
			responseText = coos.json.toJSONString(responseText);
		}
		
		callbackFunction["responseText"] = responseText;
		var args = [];
		args.push(responseText);
		if(typeof(extend) == "object" && extend !== null)
		{
			for (var property in extend)
			{
				//绑定property,可以通过函数本身调用
				callbackFunction[property] = extend[property];
				//把参数值按照顺序放入到数组中，通过apply传入
				args.push(extend[property]);
			}
		}
		//动态调用函数，把参数值数组传入
		callbackFunction.apply(this,args);
		//移除本次请求的script脚本，避免脚本不断增加
		coos.$head().removeChild(coos.$id("coos_jsonp_" + responseName));
	}
	catch(e)
	{
		//alert("实际错误消息为：" + e.message + "\n错误类型字符串为：" + e.name);
	}
};

/**
 * escape字符串，并对特殊符号作处理
 * @param str 需要处理的字符串
 * @param encode 编码方式：unencode,text,other
 */
coos.ajax.encode = function(str,encode)
{
	//不传入编码类型则默认编码
	if(typeof(encode) == "undefined"){encode = "encode";}
	//str为空或不用编码则直接返回
	if (str == null || str == "" || encode=="unencode")
	{
		return str;
	}
	var value = "";
	//value编码采用和jquery一样的处理方式
	//后台解码：java.net.URLDecoder.decode(request.getParameter("name"), "UTF-8″);
	if(encode == "text")
	{
		value = str.replace(/\n|\r|\r\n/g,"");//去掉换行符号
		value = value.replace(/<\/?.+?>/g,"");//去掉HTML标签
		value = encodeURIComponent(encodeURIComponent(value)).replace(/%20/g, "+");
	}
	else
	{
		value = encodeURIComponent(encodeURIComponent(str)).replace(/%20/g, "+");
	}
	/*
	//自定义的方法，由于后台没有统一的解码方式，不推荐使用
	else
	{
		value = escape(str);
		//替换+号为%2B
		value = value.replace(/\+/g, "%2B");
		//替换%号为%25如"%u2a2a dfd %u1f1f";替换后为%25u2a2a dfd %25u1f1f
		value = value.replace(/%u([0-9A-F]{4})/ig,function(word){return escape(word);});
	}
	//java后端没有直接的解码函数，自定义方法为：
	public static String unescape (String str)
	{
		if (str == null)
			return null;
		
		String regEx="%u([0-9A-F]{4})";
		Pattern p=Pattern.compile(regEx);
		Matcher m=p.matcher(str);
		
		StringBuffer sb = new StringBuffer();
		
		while (m.find ())
		{
			String group = m.group ().substring(2);
			m.appendReplacement(sb, String.valueOf((char)(Integer.parseInt(group,16)))); 
		}
		
		m.appendTail(sb);
		
		return sb.toString();
	}
	*/
	return value;
};

/**
 * 获取表单内容字符串,表单只有input select textarea 三种类型
 * @param formElement 表单对象或id
 */
coos.ajax.parseParameteres = function(formElement,encode)
{
	formElement = coos.$obj(formElement);
	var rs = "";
	rs += coos.ajax.getValue(formElement.getElementsByTagName("input"),"input",encode);
	rs += coos.ajax.getValue(formElement.getElementsByTagName("select"),"select",encode);
	rs += coos.ajax.getValue(formElement.getElementsByTagName("textarea"),"textarea",encode);
	return rs;
};

/**
 * 获取单个表单元素的内容
 * @param elements 表单元素对象
 * @param type 表单元素类型
 */
coos.ajax.getValue = function(elements,type,encode)
{
	var len = elements.length;
	if(len == 0)return "";
	var s = "";
	
	if(type == "input")
	{
		for (var i = 0; i < len; i++)
		{
			var obj = elements[i];
			
			if (obj.type == "hidden")
			{
				s += obj.name + "=" + coos.ajax.encode(obj.value,encode) + "&";
			}
			else if (obj.type == "text")
			{
				s += obj.name + "=" + coos.ajax.encode(obj.value,encode) + "&";
			}
			else if (obj.type == "password")
			{
				s += obj.name + "=" + coos.ajax.encode(obj.value,encode) + "&";
			}
			else if (obj.type == "checkbox")
			{
				if (obj.checked)
				{
					s += obj.name + "=" + coos.ajax.encode(obj.value,encode) + "&";
				}
			}
			else if (obj.type == "radio")
			{
				if (obj.checked)
				{
					s += obj.name + "=" + coos.ajax.encode(obj.value,encode) + "&";
				}
			}
		}
	}
	else if(type == "textarea")
	{
		for (var i = 0; i < len; i++)
		{
			var obj = elements[i];
			
			s += obj.name + "=" + coos.ajax.encode(obj.value,encode) + "&";
		}
	}
	else if(type == "select")
	{
		for (var i = 0; i < len; i++)
		{
			var obj = elements[i];
			
			if (obj.type == "select")
			{
				if (obj.selectedIndex > -1)
					s += obj.name + "=" + coos.ajax.encode(obj.options[obj.selectedIndex].value,encode) + "&";
			}
			else if (obj.type == "select-one")
			{
				if (obj.selectedIndex > -1)
					s += obj.name + "=" + coos.ajax.encode(obj.options[obj.selectedIndex].value,encode) + "&";
			}
		}
	}
	return s;
};

/**
 * 绑定ajax请求回调函数，属于内部函数
 */
coos.ajax.bindResponse = function(http_request,callbackFunction,extend)
{
	if(typeof(callbackFunction) != "function")
	{
		alert("请传入回调函数!");
		return false;
	}
	var responseText = "";
	var isTiemout = false;
	//设定5秒后请求超时
	setTimeout(function(){isTimeout = true;},5000);
	http_request.onreadystatechange = function()
	{
		if (http_request.readyState == 4 && !isTiemout)
		{
			if (http_request.status == 200)
			{
				responseText = http_request.responseText;
				try
				{
					//绑定property,可以通过函数本身调用
					callbackFunction["responseText"] = responseText;
					var args = [];
					//把responseText放入第一个位置，通过apply传入
					args.push(responseText);
					if(typeof(extend) == "object" && extend !== null)
					{
						for (var property in extend)
						{
							//绑定property,可以通过函数本身调用
							callbackFunction[property] = extend[property];
							//把参数值按照顺序放入到数组中，通过apply传入
							args.push(extend[property]);
						}
					}
					//动态调用函数，把参数值数组传入
					callbackFunction.apply(this,args);
					//eval(callbackFunction);
					
					//为避免内存泄漏，清理文档
					try{http_request = null;}catch(e){}
				}
				catch(e)
				{
					alert("实际错误消息为：" + e.message + "\n错误类型字符串为：" + e.name);
				}
			}
			else
			{
				var status = http_request.status;
				switch (status) 
				{
					case 403:
						alert("你请求的页面禁止访问!");
						break;
					case 404:
						alert("你请求的页面不存在!");
						break;	
					case 500:
						alert("你请求的页面服务器内部错误!");
						break;
					case 502:
						alert("Web服务器收到无效的响应!");
						break;
					case 503:
						alert("服务器繁忙，请稍后再试!");
						break;
					default:
						alert("你请求的页面遇到问题，操作失败!错误代码:" + status);
						break;
				}
			}
		}
		
	};
};
